Resolución numérica de ecuaciones no lineales

Introducción

Como es lógico, a la hora de emplear algún método numérico para aproximar una posible raíz de cierta ecuación lo primero que tenemos que hacer es estudiar si efectivamente dicha ecuación puede tener soluciones reales y comprobar que se dan las condiciones adecuadas para poder aplicar el método correspondiente. Por ejemplo, para poder aplicar el llamado método de bisección habrá que partir de que se dan las hipótesis del conocido teorema de Bolzano para la función  f  en cierto intervalo [a, b];  y así podremos  tener asegurada la existencia de al menos una raíz de la  ecuación f(x) = 0 en dicho intervalo.  Muchas veces lo mejor será ayudarnos previamente,  siempre que podamos, con una representación gráfica de la función en un intervalo apropiado. De esta manera, la ecuación tendrá una interpretación geométrica muy clara, como la búsqueda de los puntos de corte de la gráfica de dicha función con el eje OX.

Clear["Global`*"]

Ejemplo

Veamos en este ejemplo el caso de la función  f(x)=(e^x) - 3 en el intervalo [0, 2].

Clear[x, f, a, b]\(f[x_] := E\^x - 3; a = 0.; b = 2.; 

    graf = Plot[f[x], {x, a, b}]; \)

En todos y cada uno de los métodos que se presentan a continuación será absolutamente necesario evitar la posibilidad de entrar en un posible "bucle infinito", que dejaría bloqueado al programa e incluso al sistema operativo del ordenador en el caso de que no consigamos abortar los cálculos (mediante el correspondiente comando en el menú <Kernel>-<Abort (Evaluation)> de Mathematica). Tendremos pues que idear unos ciertos criterios de parada, de manera que el proceso se detenga cuando los resultados obtenidos se diferencien en menos de un valor determinado, que será la tolerancia o error máximo permitido, tol; o bien, cuando sean realizadas un número máximo de iteraciones, nmax, que indicaremos de antemano. Por otro lado, para la comprobación de una posible raíz exacta de la ecuación, se ha implementado una condición del tipo\(TraditionalForm
      \`|\( f(c)\) 
        |\( < ϵ\)\), siendo ϵ = (10^(-σ))con σ=$MachinePrecision; esto es debido a que, a no ser que se efectuaran todos los cálculos de forma simbólica (con la consecuente ralentización del proceso), siempre se realizan con una precisión limitada, y, por lo tanto, hay que considerar de esta manera la posibilidad de encontrar una raíz exacta de la ecuación. También se ofrece la posibilidad de solicitar todos los resultados con un número de cifras significativas determinado por el usuario (que en todo caso debe ser igual o inferior al valor de $MachinePrecision para su máquina en cuestión, que hemos tomado con un valor igual a 10; resaltamos el hecho de que este número suele ser de 6 por defecto).

\(mp = $MachinePrecision; 
precision = 10\^\(-mp\) // N; 

    cifras = 
Input[
        "Introduzca el no. de cifras con las que quiere el resultado"]; 

    tol = 10\^\(-cifras\) // N; 

    nmax = Input[\ "Introduzca el no. máximo de iteraciones:"]; 
    \)

Algoritmos de resolución numérica de ecuaciones más empleados

Métodos de Bisección y regula-falsi

A continuación tenemos la implementación del método de bisección (también llamado de bipartición).  Para obtener el algoritmo de regula-falsi bastará sustituir la línea de programa donde se calcula el valor de c como el punto medio del intervalo por la correspondiente asignación c = 
        b - (((a - b) f(b))/(f(a) - f(b))) (equivalente a  c=((af(b)-bf(a))/(f(b) - f(a)))), que sería el punto de corte de la recta secante con el eje OX.

Recuerde también que cuando se emplee este programa para aproximar una raíz de la ecuación     f(x) = 0 se debe elegir un intervalo de partida adecuado en cada caso, de manera que se verifiquen la hipótesis del teorema de Bolzano.

\(a0 = a; b0 = b; \ 
     (*\ guardamos\ los\ extremos\ del\ intervalo\ de\ partida\ *) 

    sale = "inicio"; \ 
     (*\(++\(++\(++\(++\(++\(+comienzo\)\)\)\)\)\)\ del\ algoritmo\ de\ 
        bisección*) \ \ \ \ \ 
    For[k = 1, k ≤ nmax, \(k++\), \ 
		\ c = a + \(b - a\)\/2; 
      \ \  (*\(++
              \(++\(++\(++
                    \(++\(++\(++\(++\(++\(+\ equivalente\)\)\)\)\)\)\)\)\)\)\ 
            a\ c = \(a + b\)\/2*) 
		
      If[Abs[f[c]] < precision, sale = "precision"; Break[]]; 
		
      If[Sign[f[a]] ≠ Sign[f[c]], b = c, a = c]; 
		
      If[b - a < tol, sale = "tolerancia"; Break[]\ ]
        
\ \ \ \ \ \ \ \ \ \ ]\ 
     (*\(++\(++\(++\(++\(++\(++\(++\(++\(++\(++final\)\)\)\)\)\)\)\)\)\)\ del
        \ algoritmo\ de\ bisección*) 
      

 (*
      \(++\(++\(++
              \(++\(++\(++
                    \(++\(++
                        \(++\(++
                            \(++\(++
                                \(++\(++
                                    \(++\(+impresión
                                        \)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\ de\ 
        los\ resultados*) \)\(c\&^ = SetPrecision[c, cifras]; \ 

    If[sale == "precision", 
      
Print["Posiblemente solución exacta: ", 
        c\&^], 
If[k ≤ nmax, \ 
        Print["Solución pedida: ", c\&^], 
        
Print[
          "Se llegó al no. máx. de iteraciones"]]]; 

    Print["Número de iteraciones: ", k]; 

    Print["Error máximo cometido: ", tol]; 

    Print["Solución aproximada: ", \ 
      SetPrecision[c, $MachinePrecision]]; 
a = a0; b = b0; \ 
     (*\ se\ restauran\ los\ valores\ originales\ de\ a\ y\ b\ *) \)

Vemos cómo, en efecto, se ha debido de  cumplir uno de los criterios de parada impuestos en un  número finito de iteraciones. Así pues,  el método ha sido capaz de calcular una aproximación de la raíz de la ecuación con algunas cifras decimales exactas; esto lo podemos concluir en este caso ya que una variación pequeña, que ha sido el error máximo cometido o tolerancia, podría cambiar como mucho  alguna de las últimas cifras decimales en una unidad y vemos que, en muchos de los casos, esto no afectaría por errores de redondeo a las otras.

Método de la secante

A continuación tenemos la implementación del método de la secante. Es parecido al de regula-falsi, salvo que ahora se construye iterativamente una sucesión de valores (Subscript[x, k + 1]) = 
        (Subscript[x, k]) - (((Subscript[x, k]) - (Subscript[x, k - 1]))/(f((Subscript[x, k])) - f((Subscript[x, k - 1])))) f(
              (Subscript[x, k]))  sin realizar la comprobación de cambio de signo. Ahora bien, lo mismo que ocurría al emplear el método de bisección en la sección anterior, debemos de idear algún criterio de parada cuando programamos cualquier método iterativo. Lo que haremos ahora, al no poder controlar de forma tan clara como en el método de bisección el error absoluto cometido,  es fijarnos en la diferencia entre dos iteraciones consecutivas, parando el proceso cuando ésta sea inferior a la tolerancia prefijada, tol; también fijaremos un número máximo de iteraciones a realizar, en caso de que dicha tolerancia sea dificil de alcanzar en un número de iteraciones razonable.

\(x0 = a // N; x1 = b // N; \ \ 
     (*valor\ numérico\ de\ los\ extremos\ del\ intervalo*) 
      
\ 
     (*\(++\(++
            \(++\(++\(++
                  \(++\(++
                      \(++\(++
                          \(++\(++
                              \(++\(++
                                  \(++\(+comienzo
                                      \)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\ del\ 
        algoritmo\ de\ la\ secante*) 
For[k = 1, 
      k ≤ nmax, \(k++\), 
\ \ \ \ 
      c = x1 - \(\((x0 - x1)\) f[x1]\)\/\(f[x0] - f[x1]\); \ x0 = x1; \ 
      x1 = c; 
	If[Abs[f[c]] < precision, sale = "precision"; Break[]]; 
      
	If[Abs[x1 - x0] < tol, sale = "tolerancia"; Break[]\ ]
        
\ \ \ \ \ \ \ \ \ \ ]\ \ 
     (*\(++\(++
            \(++\(++\(++
                  \(++\(++
                      \(++\(++\(++\(++\(++\(+final\)\)\)\)\)\)\)\)\)\)\)\)\)\ 
        del\ algoritmo\ de\ la\ secante*) 
 (*
      \(++\(++\(++
              \(++\(++\(++
                    \(++\(++
                        \(++\(++
                            \(++\(++
                                \(++\(++
                                    \(++\(++
                                        \(++\(++
                                        \(+\(+impresión
                                        \)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\ de\ los\ resultados*) \)\(c\&^ = SetPrecision[c, cifras]; 

    If[sale == "precision", 
      
Print["Posiblemente solución exacta: ", 
        c\&^], 
If[k ≤ nmax, \ 
        
Print["Solución pedida: ", c\&^], 
        
Print[
          "Se llegó al no. máx. de iteraciones"]\ ]\ ]; 

    Print["Número de iteraciones: ", k]; 

    Print["Error máximo cometido: ", tol]; 

    Print["Solución aproximada: ", \ 
      SetPrecision[c, $MachinePrecision]]; 
a = a0; b = b0; \ 
     (*\ se\ restauran\ los\ valores\ originales\ de\ a\ y\ b\ *) \)

Métodos de Whittaker y Newton-Rapshon

Vamos a implementar en esta sección el llamado método de Whittaker que, a partir de un valor inicial (Subscript[x, 0]), utiliza en principio rectas con pendiente fijada para calcular el punto de corte de éstas con el eje OX para aproximar la raíz buscada. No obstante, empleando el programa resultante y permitiendo variar dichas pendientes (m = f' ((Subscript[x, k])), k ≥ 0), para que sean las de la recta tangente en el punto ((Subscript[x, k]), f((Subscript[x, k]))), obtendríamos el conocido método de  Newton-Raphson. También se verá que para que este método funcione correctamente será necesario que la derivada de la función no esté próxima a cero, al menos en cierto entorno de la raíz, ya que de lo contrario se podría producir una división entre cero o bien la creación de enormes errores de redondeo al dividir entre cantidades muy pequeñas.

Sigamos pues con el ejemplo que teníamos desde el principio de la práctica y representemos gráficamente todo este proceso.

\(f[x_] := E\^x - 3; 
a = 0.; b = 2.; 
x0 = b; \ m = 10; 

    x1 = x0 - f[x0]\/m; 
y[x_] := f[x0] + m\ \((x - x0)\)\)\(graf = 
      Plot[{f[x], y[x]}, {x, a, b}, 
	
        Ticks -> {{{x0, "x0", {0.01, 0.01}}, {x1, 
                "x1", {0.01, 0.01}}}, Automatic}\ 
         (*\ con\ la\ opcion\ Ticks\ ponemos\ marcas\ en\ los\ ejes\ de\ 
            coordenadas\ *) , DisplayFunction -> Identity]; 

    Show[graf, Graphics[{PointSize[.02], Point[{x0, f[x0]}]}], 
      DisplayFunction :> $DisplayFunction]; \)

De esta manera, y repitiendo este proceso, se llega a una sucesión iterativa, que, si se dan ciertas condiciones apropiadas, va a converger hacia la verdadera raíz de nuestra ecuación. Para ello habrá que elegir convenientemente el valor de la pendiente m, ya que basta probar con ciertos valores de esta pendiente para darnos cuenta cómo nos aproximamos más y más a la raíz, o por el contrario ocurre todo lo contrario. Animamos al lector a realizar algunos cambios en el valor de m en la gráfica anterior y comprobarlo por sí mismo.

sale = "inicio"; x0 = b; m = 10;
   
For[k = 1,k ≤ nmax,k++,
(* m=f'[x0];  +++++++++++++en el caso del
                     método de Newton - Raphson*)
\(\(x1 = x0 - f[x0]\/m; \)\ 

            	
            \(If[Abs[f[x1]] < precision, \ sale = "precision"; Break[]]; 
            \)

            \ \ \ \ 
            \(If[Abs[x1 - x0] < tol, \ sale = "tolerancia"; \ Break[]]; 
            \)

            x0 = x1\)];

\(\( (*
      \(++\(++\(++
              \(++\(++\(++
                    \(++\(++
                        \(++\(++
                            \(++\(++
                                \(++\(++
                                    \(++\(++
                                        \(++\(++
                                        \(+impresión
                                        \)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\ de\ los\ resultados*) 
x2 = SetPrecision[x1, cifras]; 

    If[sale == "precision", \ 
	
      Print["Posible solución exacta: ", x2], 
      
If[k ≤ nmax, 
        
Print["Solución pedida: ", \ x2], 
        
Print[
          "Se llegó al no. máx. de iteraciones"]\ ]]; 

    Print["Número de iteraciones: ", k]; 

    Print["Diferencia máxima entre iteraciones:", tol]; 

    Print["Solución aproximada: ", 
\ 
      SetPrecision[x1, $MachinePrecision]]; \)\)

Mathematica incorpora una orden directa para realizar el algoritmo de Newton-Raphson, sin necesidad de acudir al código ya implementado anteriormente, y que permite aumentar considerablemente el número de cifras significativas que se pueden considerar, aumentando así la precisión en los cálculos. Dicha orden tiene el siguiente formato:  FindRoot[ecuación, {x, x0, a, b}, Opciones], donde ecuación es una ecuación bien formada en el lenguaje de Mathematica o bien simplemente la función f(x)a la que queremos calcularle sus ceros;  x0 es el valor inicial para comenzar las iteraciones, y  a, b son opcionalmente los extremos del intervalo en el que queremos calcular dicha raíz. En cuanto a las opciones disponibles, lo mejor es mirar el manual de Mathematica o bien preguntarle directamente al núcleo, mediante la orden de interrogación ?.

?FindRoot

Veamos un ejemplo

FindRoot[f[x], {x, 2.}]

Vemos que, por defecto, aunque internamente los cálculos se efectuan con una precisión de 16 cifras signiticativas, sólo se nos presentan 6 de ellas. Por lo tanto si queremos que se nos muestren más podemos escribir  SetPrecision[ valor, cifras], donde cifras deberá ser un entero no superior a  $MachinePrecision.

SetPrecision[%, 10]

Por el contrario, si lo que queremos es obtener el valor de dicha raíz con una precisión más elevada, lo que deberemos de hacer es aumentar el valor de la opción WorkingPrecision dentro de la orden  FindRoot. Veamos un ejemplo:

FindRoot[f[x], {x, 2.}, WorkingPrecision -> 100]

Métodos de iteración funcional: casos particulares de los métodos de Newton-Raphson y Steffensen

En los métodos de iteración funcional lo que se pretende es encontrar un punto fijo de la aplicación  g : I -> I  para cierto subconjunto cerrado de la recta real (no necesariamente acotado) mediante una sucesión de valores (Subscript[x, k + 1]) = g((Subscript[x, k])),  k ≥ 0. En el caso del método de Newton-Raphson, bastará con tomar  g(x) = x - ((f(x))/(f' (x))), obteniéndose convergencia cuadrática en la mayoría de los casos.  Lo mismo ocurre con el denominado método de Steffensen, en el que se tomaría g(x) = x - (((f(x))^2)/(f(x + f(x)) - f(x))), y que no debe confundirse con el método de aceleración de la convergencia del mismo nombre.

\(f[x_] := E\^x - 3; 
\ g[x_] := x - f[x]\/\(f'\)[x]\ ; 
     (*\ en\ el\ caso\ del\ método\ de\ Newton - Raphson\ *) 
      
 (*\ 
      g[x_] := x - 
          f[x]\^2\/\(f[x + f[x]] - f[x]\)\ \ en\ el\ caso\ del\ método
            \ de\ Steffensen\ *) 
a = 0.; b = 2.; x0 = b; \ x1 = g[x0]; 

    graf = Plot[{g[x], x}, {x, a, b}, 
        Ticks -> {{{x0, "x0", {0.01, 0.01}}, {x1, 
                "x1", {0.01, 0.01}}}, Automatic}\ 
         (*\ con\ la\ opcion\ Ticks\ ponemos\ marcas\ en\ los\ ejes\ de\ 
            coordenadas\ *) , DisplayFunction -> Identity]; 

    Show[graf, Graphics[{PointSize[.02], Point[{x0, g[x0]}]}], 
      DisplayFunction :> $DisplayFunction]; \)

\(\(\ sale = "inicio"; \ 
x0 = 2.; \ aproxIt = {x0}; 
    
\ 
     (*\(++\(++\(++\(++\(++\(++\(++\(++\(++comienzo\)\)\)\)\)\)\)\)\)\ del\ 
        algoritmo\ de\ iteración\ funcional*) 

    For[k = 1, k ≤ nmax, \(k++\), 
	x1 = g[x0]; 
      \ AppendTo[aproxIt, x1]; 
\ \ \ \ 
      If[Abs[x1 - x0] < tol, \ sale = "tolerancia"; \ Break[]]; 
      
x0 = x1]; \ \ 
     (*\(++\(++\(++\(++\(++final\)\)\)\)\)\ del\ algoritmo\ de\ 
        iteración\ funcional*) 
      

 (*
      \(++\(++\(++
              \(++\(++\(++
                    \(++\(++
                        \(++\(++
                            \(++\(++
                                \(+\(++
                                    \(++\(++
                                        \(++\(++
                                        \(+impresión
                                        \)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\)\ de\ los\ resultados*) 
x2 = SetPrecision[x1, cifras]; 

    If[sale == "precision", \ 
	
      Print["Posible solución exacta: ", x2], 
      
If[k ≤ nmax, 
        
Print["Solución pedida: ", \ x2], 
        
Print[
          "Se llegó al no. máx. de iteraciones"]\ ]\ ]; 

    Print["Número de iteraciones: ", k]; 

    Print["Diferencia máxima entre iteraciones:", tol]; 

    Print["Solución aproximada: ", 
\ 
      SetPrecision[x1, $MachinePrecision]]; \)\)

Podemos conocer  las sucesivas aproximaciones obtenidas, ya que las hemos ido guardando en la lista  aproxIt

\(Print["Sucesión de aproximaciones:"]; 

    SetPrecision[aproxIt, cifras]\)

Órdenes directas de Mathematica

Una ecuación se escribe en Mathematica mediante una expresión lógica de igualdad (con dos signos igual '=')    (Subscript[expr, 1]) ==  (Subscript[expr, 2]). A su vez Mathematica dispone de dos tipos de métodos para la resolución de ecuaciones:  de resolución simbólica y mediante aproximaciones numéricas. En general, para resolver una ecuación formalmente, es decir de manera simbólica, se puede hacer uso principalmente de la orden     Solve[ecuación, variable]    mientras que para hacerlo numéricamente, de forma aproximada, lo podremos realizar mediante la orden     NSolve[ecuación, variable]. El único inconveniente es que, salvo para un número muy reducido de ecuaciones, entre las que se encontrarán las de tipo polinómico de grado bajo, lo más probable es que no se puedan encontrar todas las posibles soluciones de la ecuación.

Resolución de ecuaciones  en general

Veamos algunos ejemplos:

Solve[Sin[x] Cos[x] == 0, x]

Observará que aparece un mensaje indicando que, debido al método de resolución empleado, puede que no se encuentren todas las posibles soluciones. Veamos ahora que pasa con  NSolve:

NSolve[Sin[x] Cos[x] == 0, x]

Vemos que aparece el mismo mensaje que antes, sólo que ahora las soluciones se muestran con decimales en vez de forma exacta como antes. Si queremos aumentar el número de cifras significativas presentadas, deberemos combinar esta sentencia con las ya concocidas órdenes de Mathematica  SetPrecision o mediante la opción  WorkingPrecision->  dentro de  NSolve.

SetPrecision[NSolve[Sin[x] Cos[x] == 0, x], 10]

NSolve[Sin[x] Cos[x] == 0, x, WorkingPrecision -> 100]

Veamos ahora otra sentencia, Reduce , que tiene como objetivo la simplificación lógica previa de la ecuación antes de pasar a su resolución. Es decir que se reduce la ecuación a un conjunto de ecuaciones o relaciones más sencillas, realizando una distinción adecuada de los posibles casos en la variable independiente. Así pues, la salida que produce  Reduce  es por tanto un conjunto de igualdades o relaciones lógicas, conectadas mediante los operadores lógicos usuales  "y" (&&) u  "o"  (||).

Reduce[Sin[x] Cos[x] == 0, x]

Además, en el caso de que aparezcan ciertos parámetros en la ecuación, esta orden realiza un estudio de casos según los posibles valores que puedan tomar dichos parámetros; cosa que no hace la sentencia  Solve. Comparar las salidas de los siguientes ejemplos:

Clear[a]Solve[(1/a) Exp[x + 1] - 3  (a^2) == 0, x]Solve[(1/a) Exp[x + 1] - 3  (a^2) == 0, a, x]

Recordamos que, para preguntarle al propio núcleo ('Kernel') de Mathematica por el efecto y formato de la sentencia  Solve, bastará con preguntárselo mediante el signo de interrogación:

?Solve

?Reduce

Reduce[(1/a)  Exp[x + 1] - 3  (a^2) == 0, x]Reduce[(1/a)  Exp[x + 1] - 3  (a^2) == 0, a, x]

Veamos algunos ejemplos más:

Clear[x]sols = Solve[((1 - (Sqrt[x]))/(x^2)) == (Sqrt[x - 1]), x]

Aquí vemos como no es capaz de calcular todas las soluciones de la ecuación; sino que muchas de ellas las deja indicadas, resultando ser los ceros del siguiente polinomio  -1+x-2(x^4) - 2  (x^5) - (x^8) + (x^9) que veremos en la siguiente sección cómo se pueden calcular mediante una sentencia propia para estos casos.

% // N

Aquí ha calculado dos raíces, complejas conjugadas, del  polinomio  -1+x-2(x^4) - 2  (x^5) - (x^8) + (x^9) pero no las ha calculado todas. Pero como hemos indicado Mathematica dispone de sentencias específicas para calcular los ceros de cualquier polinomio.

Resolución de ecuaciones polinómicas con  Mathematica

La sentencia  Roots[polinomio==0, x]     obtiene todas las raíces reales y complejas de la ecuación polinómica correspondiente generando una lista con las mismas tal y como se observa  en el siguiente ejemplo:

Clear[x]raices = 
      Roots[-1 + x - 2  (x^4) - 2  (x^5) - (x^8) + (x^9) == 0, x]

De manera que, en caso de no haber sido capaz de calcularlas de manera exacta, podremos obtener una aproximación numérica mediante alguna de las órdenes  N o SetPrecision.

% // N

SetPrecision[raices, 10]

Sin embargo, para polinomios de grado bajo, ésto no será necesario generalmente. Vea detenidamente los ejemplos siguientes e intente darse cuenta de las pequeñas diferencias:

Roots[((x^2) + 9) (x - (5/2)) == 0, x]

Roots[((x^2) + 9) (x - 2.5) == 0, x]

Solve[((x^2) + 9) (x - 2.5) == 0, x]

Vemos en este último caso, cómo la sentencia  Solve  ha servido igualmente para obtener las raíces de este polinomio de grado  3.  No obstante  debido a los inevitables errores de redondeo, puede ser interesante que aquellos valores muy próximos a cero sean redondeados y se les dé el valor nulo. Esto se puede hacer mediante la sentencia  Chop.

Chop[%]

Veámos algunos ejemplos más:

Solve[(x^4) - 3 (x^3) + x == 0, x]

NSolve[(x^19) + 9 (x^13) + 4 (x^6) + 2 x - 25 == 0, x]

Es conveniente, en este caso, pedir a Mathematica que efectúe directamente una aproximación decimal,  con la orden  NSolve  en vez de  Solve; o bien expresando alguno de sus coeficientes en forma decimal:

NSolve[(x^19) + 9 (x^13) + 4 (x^6) + 2 x - 25. == 0, x]

Observe ahora la salida de las dos órdenes siguientes:

SetPrecision[Chop[Roots[(x^5) + x - 1 == 0, x]], 10]

SetPrecision[Chop[Solve[(x^5) + x - 1 == 0, x]], 10]

NSolve[(x^5) + x - 1 == 0, x]

NRoots[(x^5) + x - 1 == 0 == 0, x]

Ejercicios

1.- Demuestre que la ecuación  (x^3) + 4 (x^2) = 10  tiene una única raíz en el intervalo [1, 2].  Aproxime dicha raíz con el método de bisección con al menos 3 cifras decimales exactas. ¿Cuántas iteraciones serán necesarias para conseguir 5 cifras decimales exactas?  Aproxime también la raíz con el método de Newton-Raphson partiendo del extremo adecuado hasta que la diferencia en valor absoluto, entre dos aproximaciones consecutivas sea  inferior a  (10^(-3)).

2.- Encuentre una aproximación de la raíz cúbica de 25 con dos decimales exactos, usando el algoritmo de bisección.

3.- Use el método de Newton-Raphson para aproximar las soluciones de las siguientes ecuaciones con precisión (10^(-5)) , partiendo de un valor adecuado, próximo a cada una de ellas en cada caso.
i) (x^3) - x - 1=0  en [1, 2].
ii) 3  x = 2 + (x^2) - (e^x).
iii) (x^2) + 10 cos x + x=0.

4.- Para la función   f(x)= 3(x^2) + (e^x) - 1, 
i) encuentre, mediante el método de bisección una aproximación de la raíz en [0,1] con, al menos, cuatro decimales exactos, y determinel número de iteraciones realizadas;
ii) encuentre, mediante el método de Newton-Raphson, una aproximación de la raíz en [0, 1] con una tolerancia de (10^(-4)), partiendo de x0=0, y determine el número de iteraciones realizadas.

5.- Utilice las órdenes apropiadas de Mathematica para aproximar todos los puntos donde se anulan las funciones siguientes (si es neceario, represéntelas gráficamente):
i) f(x) = (x^7) - (x^4) + 2,
ii) f(x) = (x^7) + cos x - 3.

6.- Programar el método de Newton-Raphson acelerado para el caso de una raíz múltiple de una ecuación y comparar los resultados con los que se obtienen mediante el empleo de los métodos de aceleración anteriores.